﻿using System;
using System.Linq;
using System.Reflection;
using System.Runtime;
using System.Threading.Tasks;
using Jy.Abp.Settings;
using Jy.Utilities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SettingManagement;
using Volo.Abp.Settings;

namespace Jy.Abp.SettingManagement;

public class TypedSettingsManager : ITypedSettingsManager, ITransientDependency
{
    private readonly ISettingManager _settingManager;
    private readonly ITypedSettingsValueSerializer _valueSerializer;
    public TypedSettingsManager(ISettingManager settingManager, ITypedSettingsValueSerializer valueSerializer)
    {
        _settingManager = settingManager;
        _valueSerializer = valueSerializer;
    }

    public virtual async Task<TSettings> GetAsync<TSettings>(string providerName, string providerKey, bool fallback = true)
        where TSettings : ITypedSettings
    {
        var settings = TypedSettingsHelper.CreateInstance<TSettings>();
        var ps = typeof(TSettings).GetProperties();
        foreach (var p in ps)
        {
            var settingName = TypedSettingsHelper.CreateSettingName(p);
            var settingVal = await this._settingManager.GetOrNullAsync(settingName, providerName, providerKey, fallback);
            var propertyVal = this._valueSerializer.Deserialize(p.PropertyType, settingVal);
            p.SetValue(settings, propertyVal);
        }
        return settings;
    }

    public virtual async Task SetAsync<TSettings>(TSettings settings, string providerName, string providerKey, bool forceToSet = false)
        where TSettings : ITypedSettings
    {
        Check.NotNull(settings, nameof(settings));
        var type = typeof(TSettings);
        foreach (var p in type.GetProperties())
        {
            var settingName = TypedSettingsHelper.CreateSettingName(p);
            var val = this._valueSerializer.Serialize(p.GetValue(settings));
            await this._settingManager.SetAsync(settingName, val, providerName, providerKey, forceToSet);
        }
    }
}
